package health_system.health_system.websocket.Server;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import health_system.health_system.websocket.Model.*;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.util.AttributeKey;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import javax.net.ssl.KeyManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 基于Netty实现的聊天WebSocket服务器
 * 处理用户间的文字、图片、短视频、语音消息、文件传输及社交功能
 */
@Component
public class NettyChatMessageServer {
    private static final Logger logger = Logger.getLogger(NettyChatMessageServer.class.getName());
    
    // 用户会话映射，保存所有在线用户的WebSocket通道
    private static final Map<String, Channel> channelMap = new ConcurrentHashMap<>();
    
    // 好友关系映射，保存用户的好友列表
    private static final Map<String, Set<String>> friendsMap = new ConcurrentHashMap<>();
    
    // JSON序列化工具
    private static final ObjectMapper mapper = new ObjectMapper();
    
    // 系统消息常量
    private static final String SYSTEM_NAME = "系统";
    private static final String USER_OFFLINE_MESSAGE = "用户当前不在线，消息将在其上线后发送";
    
    // 消息类型的最大尺寸（字节）
    private static final Map<MessageContentType, Long> MAX_SIZE_LIMITS = new HashMap<>();
    
    // 用于存储分块消息的临时缓存
    private static final Map<String, Map<Integer, String>> chunkCache = new ConcurrentHashMap<>();
    private static final Map<String, ChatMessage> chunkMetadataCache = new ConcurrentHashMap<>();
    
    // 用于存储用户名的属性键
    private static final AttributeKey<String> USERNAME_ATTR = AttributeKey.valueOf("username");
    
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel serverChannel;
    
    @Value("${netty.chat.port:8086}")
    private int port;
    
    @Value("${netty.ssl.enabled:false}")
    private boolean sslEnabled;
    
    @Value("${netty.ssl.key-store:}")
    private String keyStorePath;
    
    @Value("${netty.ssl.key-store-type:PKCS12}")
    private String keyStoreType;
    
    @Value("${netty.ssl.key-store-password:}")
    private String keyStorePassword;
    
    @Value("${netty.ssl.key-alias:}")
    private String keyAlias;
    
    static {
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        
        // 初始化各类型消息的大小限制
        MAX_SIZE_LIMITS.put(MessageContentType.TEXT, 400* 1024L);          // 4KB
        MAX_SIZE_LIMITS.put(MessageContentType.IMAGE, 50 * 1024 * 1024L); // 10MB
        MAX_SIZE_LIMITS.put(MessageContentType.VIDEO, 50 * 1024 * 1024L); // 50MB
        MAX_SIZE_LIMITS.put(MessageContentType.AUDIO, 50 * 1024 * 1024L);  // 5MB
        MAX_SIZE_LIMITS.put(MessageContentType.FILE, 100 * 1024 * 1024L); // 100MB
    }
    
    /**
     * 启动Netty WebSocket服务器
     */
    public void start() throws Exception {
        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup();
        
        try {
            // 创建SSL上下文（如果启用）
            final SslContext sslContext = createSslContext();
            
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            
                            // 添加SSL处理器（如果启用）
                            if (sslContext != null) {
                                pipeline.addLast(sslContext.newHandler(ch.alloc()));
                            }
                            
                            // HTTP请求解码器
                            pipeline.addLast(new HttpServerCodec());
                            // 聚合HTTP消息
                            pipeline.addLast(new HttpObjectAggregator(65536));
                            // 处理大数据流
                            pipeline.addLast(new ChunkedWriteHandler());
                            // WebSocket处理器
                            pipeline.addLast(new ChatWebSocketHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);
            
            Channel channel = bootstrap.bind(port).sync().channel();
            this.serverChannel = channel;
            
            logger.info("Netty 聊天 WebSocket 服务器启动成功，端口: " + port + 
                       (sslEnabled ? " (SSL启用)" : ""));
            
            // 等待服务器关闭
            channel.closeFuture().sync();
        } finally {
            shutdown();
        }
    }
    
    /**
     * 关闭Netty WebSocket服务器
     */
    public void shutdown() {
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
        logger.info("Netty 聊天 WebSocket 服务器已关闭");
    }
    
    /**
     * 创建SSL上下文
     * @return SSL上下文，如果未启用SSL则返回null
     */
    private SslContext createSslContext() {
        if (!sslEnabled) {
            return null;
        }
        
        try {
            // 检查keystore配置
            if (keyStorePath == null || keyStorePath.isEmpty() || 
                keyStorePassword == null || keyStorePassword.isEmpty()) {
                logger.warning("SSL已启用，但keystore路径或密码未配置");
                return null;
            }
            
            // 加载keystore文件
            String keystoreFilePath = keyStorePath;
            if (keystoreFilePath.startsWith("classpath:")) {
                keystoreFilePath = keystoreFilePath.substring("classpath:".length());
            }
            
            ClassPathResource resource = new ClassPathResource(keystoreFilePath);
            if (!resource.exists()) {
                logger.warning("Keystore文件不存在: " + keyStorePath);
                return null;
            }
            
            // 创建KeyStore实例
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            try (InputStream keyStoreStream = resource.getInputStream()) {
                keyStore.load(keyStoreStream, keyStorePassword.toCharArray());
            }
            
            // 创建KeyManagerFactory
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(keyStore, keyStorePassword.toCharArray());
            
            // 构建SslContext
            return SslContextBuilder.forServer(kmf).build();
            
        } catch (Exception e) {
            logger.log(Level.SEVERE, "创建SSL上下文失败: " + e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 从查询字符串中提取用户名
     * @param queryString 查询字符串
     * @return 用户名，如果未找到则返回null
     */
    private static String extractUsernameFromQueryString(String queryString) {
        if (queryString == null || !queryString.contains("username=")) {
            return null;
        }
        
        String[] parts = queryString.split("username=");
        if (parts.length < 2) {
            return null;
        }
        
        String username = parts[1];
        int ampIndex = username.indexOf('&');
        if (ampIndex != -1) {
            username = username.substring(0, ampIndex);
        }
        
        return username;
    }
    
    /**
     * 发送消息到指定通道
     */
    private void send(Channel channel, ChatMessage message) {
        try {
            String jsonMessage = mapper.writeValueAsString(message);
            send(channel, jsonMessage);
        } catch (JsonProcessingException e) {
            logger.log(Level.SEVERE, "序列化消息失败", e);
        }
    }
    
    /**
     * 发送文本消息到指定通道
     */
    private void send(Channel channel, String message) {
        if (channel == null || !channel.isActive()) {
            logger.warning("尝试向无效通道发送消息");
            return;
        }
        
        try {
            logger.fine("发送消息: " + message);
            // 消息大小限制在Netty框架内处理，这里直接发送
            TextWebSocketFrame frame = new TextWebSocketFrame(message);
            channel.writeAndFlush(frame);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "发送消息时出错", e);
        }
    }
    
    /**
     * 发送系统消息给指定用户
     */
    private void sendSystemMessageToUser(String username, String content) {
        Channel userChannel = channelMap.get(username);
        if (userChannel != null && userChannel.isActive()) {
            ChatMessage systemMessage = new ChatMessage();
            systemMessage.setType(MessageType.SYSTEM_NOTIFICATION.getValue());
            systemMessage.setFromUser(SYSTEM_NAME);
            systemMessage.setToUser(username);
            systemMessage.setContentType(MessageContentType.TEXT.getValue());
            systemMessage.setContent(content);
            systemMessage.setTimestamp(System.currentTimeMillis());
            systemMessage.setMessageId(generateMessageId());
            
            send(userChannel, systemMessage);
        }
    }
    
    /**
     * 发送错误消息给指定用户
     */
    private void sendErrorToUser(String username, String errorMessage) {
        Channel userChannel = channelMap.get(username);
        if (userChannel != null && userChannel.isActive()) {
            ChatMessage errorMsg = new ChatMessage();
            errorMsg.setType(MessageType.ERROR.getValue());
            errorMsg.setFromUser(SYSTEM_NAME);
            errorMsg.setToUser(username);
            errorMsg.setContentType(MessageContentType.TEXT.getValue());
            errorMsg.setContent(errorMessage);
            errorMsg.setTimestamp(System.currentTimeMillis());
            
            send(userChannel, errorMsg);
        }
    }
    
    /**
     * 生成唯一消息ID
     */
    private String generateMessageId() {
        return UUID.randomUUID().toString();
    }
    
    /**
     * 处理WebSocket连接打开事件
     */
    private void handleWebSocketOpen(Channel channel, String queryString) {
        String username = extractUsernameFromQueryString(queryString);
        
        if (username != null) {
            // 将用户名保存到通道属性中
            channel.attr(USERNAME_ATTR).set(username);
            // 将通道添加到映射中
            channelMap.put(username, channel);
            logger.info("用户上线: " + username);
            
            // 如果是新用户，初始化好友列表
            friendsMap.putIfAbsent(username, ConcurrentHashMap.newKeySet());
            
            // 在测试环境中，自动添加常用测试用户为好友关系
            addTestFriends(username);
            
            // 通知该用户的好友其已上线
            notifyFriendsOfStatusChange(username, true);
            
            // 发送离线消息（实际实现中需要从数据库获取）
            sendOfflineMessages(username);
        } else {
            logger.warning("无效的用户名参数");
            channel.close();
        }
    }
    
    /**
     * 处理WebSocket连接关闭事件
     */
    private void handleWebSocketClose(Channel channel) {
        String username = channel.attr(USERNAME_ATTR).get();
        
        if (username != null && channelMap.containsKey(username)) {
            logger.info(username + " 已离线");
            channelMap.remove(username);
            
            // 通知该用户的好友其已离线
            notifyFriendsOfStatusChange(username, false);
        }
    }
    
    /**
     * 处理WebSocket消息
     */
    private void handleWebSocketMessage(Channel channel, String message) {
        if (message == null || message.isEmpty()) {
            logger.warning("收到空消息");
            return;
        }
        
        logger.fine("收到消息: " + message);
        
        try {
            ChatMessage chatMessage = mapper.readValue(message, ChatMessage.class);
            String messageType = chatMessage.getType();
            String fromUser = chatMessage.getFromUser();
            
            // 处理分块消息
            if ("chunk_metadata".equals(messageType)) {
                handleChunkMetadata(chatMessage);
                return;
            } else if ("chunk".equals(messageType)) {
                handleMessageChunk(chatMessage);
                return;
            }
            
            MessageType type = MessageType.fromString(messageType);
            
            if (type == null || fromUser == null) {
                logger.warning("无效的消息格式: 缺少必要字段");
                return;
            }
            
            switch (type) {
                case CHAT_MESSAGE:
                    handleChatMessage(chatMessage);
                    break;
                case FRIEND_REQUEST:
                    handleFriendRequest(chatMessage);
                    break;
                case FRIEND_RESPONSE:
                    handleFriendResponse(chatMessage);
                    break;
                case SOCIAL_POST:
                    handleSocialPost(chatMessage);
                    break;
                case SOCIAL_INTERACTION:
                    handleSocialInteraction(chatMessage);
                    break;
                case TYPING_INDICATOR:
                    handleTypingIndicator(chatMessage);
                    break;
                case READ_RECEIPT:
                    handleReadReceipt(chatMessage);
                    break;
                case MEDIA_TRANSFER:
                    handleMediaTransfer(chatMessage);
                    break;
                case MEDIA_TRANSFER_START:
                    handleMediaTransferStart(chatMessage);
                    break;
                case MEDIA_TRANSFER_COMPLETE:
                    handleMediaTransferComplete(chatMessage);
                    break;
                default:
                    logger.warning("未处理的消息类型: " + type);
            }
        } catch (Exception e) {
            logger.log(Level.SEVERE, "处理消息时出错: " + e.getMessage(), e);
        }
    }
    
    /**
     * 处理聊天消息
     */
    private void handleChatMessage(ChatMessage message) throws IOException {
        String toUser = message.getToUser();
        String fromUser = message.getFromUser();
        
        // 验证消息大小是否符合限制
        if (!validateMessageSize(message)) {
            sendErrorToUser(fromUser, "消息超出大小限制");
            return;
        }
        
        // 检查是否来自测试页面的消息(通常测试页面的用户名是数字或特定格式)
        boolean isTestMessage = isTestUser(fromUser) || isTestUser(toUser);
        
        // 验证发送者和接收者是否为好友关系（测试消息可以跳过好友验证）
        if (!isTestMessage && !areFriends(fromUser, toUser)) {
            sendErrorToUser(fromUser, "无法发送消息，对方不是您的好友");
            return;
        }
        
        // 生成消息ID和时间戳
        message.setMessageId(generateMessageId());
        message.setTimestamp(System.currentTimeMillis());
        
        // 标记消息为未读
        message.setRead(false);
        
        Channel toUserChannel = channelMap.get(toUser);
        
        if (toUserChannel != null && toUserChannel.isActive()) {
            // 接收者在线，直接发送消息
            send(toUserChannel, message);
            
            // 发送发送成功的确认给发送者
            sendDeliveryConfirmation(fromUser, message.getMessageId(), DeliveryStatus.SENT);
        } else {
            // 接收者不在线，存储离线消息
            // 注：实际实现中应存储到数据库，这里仅发送通知
            logger.info("用户" + toUser + "不在线，消息将稍后发送");
            
            // 发送离线通知给发送者
            sendDeliveryConfirmation(fromUser, message.getMessageId(), DeliveryStatus.PENDING);
        }
    }
    
    /**
     * 判断是否是测试用户
     */
    private boolean isTestUser(String username) {
        // 测试用户通常是数字ID或特定格式
        return username != null && (
            username.matches("\\d+") ||  // 纯数字ID
            username.startsWith("test") ||
            username.startsWith("user")
        );
    }
    
    /**
     * 处理好友请求
     */
    private void handleFriendRequest(ChatMessage message) throws IOException {
        String fromUser = message.getFromUser();
        String toUser = message.getToUser();
        
        Channel toUserChannel = channelMap.get(toUser);
        
        if (toUserChannel != null && toUserChannel.isActive()) {
            // 用户在线，发送好友请求
            send(toUserChannel, message);
        } else {
            // 用户不在线，存储离线请求
            // 注：实际实现中应存储到数据库
            sendSystemMessageToUser(fromUser, "用户" + toUser + "当前不在线，请求将在其上线后发送");
        }
    }
    
    /**
     * 处理好友请求响应
     */
    private void handleFriendResponse(ChatMessage message) throws IOException {
        String fromUser = message.getFromUser();
        String toUser = message.getToUser();
        Boolean accepted = Boolean.parseBoolean(message.getContent());
        
        if (accepted) {
            // 接受好友请求，更新好友关系
            addFriend(fromUser, toUser);
            
            // 通知双方好友关系已建立
            sendSystemMessageToUser(fromUser, "您已添加 " + toUser + " 为好友");
            sendSystemMessageToUser(toUser, fromUser + " 已接受您的好友请求");
        } else {
            // 拒绝好友请求，通知发送方
            sendSystemMessageToUser(toUser, fromUser + " 拒绝了您的好友请求");
        }
    }
    
    /**
     * 处理朋友圈发布
     */
    private void handleSocialPost(ChatMessage message) throws IOException {
        String fromUser = message.getFromUser();
        
        // 生成朋友圈消息ID和时间戳
        message.setMessageId(generateMessageId());
        message.setTimestamp(System.currentTimeMillis());
        
        // 处理媒体内容（实际实现中应存储到服务器）
        if (!MessageContentType.TEXT.getValue().equals(message.getContentType())) {
            // 处理媒体文件存储和URL生成
            String mediaUrl = processAndStoreMediaContent(message);
            message.setContent(mediaUrl);
        }
        
        // 获取发布者的所有好友
        Set<String> friends = friendsMap.getOrDefault(fromUser, Collections.emptySet());
        
        // 通知所有在线好友有新动态
        for (String friend : friends) {
            Channel friendChannel = channelMap.get(friend);
            if (friendChannel != null && friendChannel.isActive()) {
                send(friendChannel, message);
            }
            // 对不在线的好友，实际实现中应存储到数据库，待上线后通知
        }
        
        // 发送确认给发布者
        sendSystemMessageToUser(fromUser, "朋友圈动态已发布");
    }
    
    /**
     * 处理社交互动（点赞、评论等）
     */
    private void handleSocialInteraction(ChatMessage message) throws IOException {
        String fromUser = message.getFromUser();
        String toUser = message.getToUser();
        String postId = message.getRelatedMessageId();
        SocialInteractionType interactionType = SocialInteractionType.fromString(message.getContent());
        
        if (interactionType == null || postId == null) {
            sendErrorToUser(fromUser, "无效的社交互动请求");
            return;
        }
        
        // 生成互动ID和时间戳
        message.setMessageId(generateMessageId());
        message.setTimestamp(System.currentTimeMillis());
        
        // 通知帖子所有者有新互动
        Channel toUserChannel = channelMap.get(toUser);
        if (toUserChannel != null && toUserChannel.isActive()) {
            send(toUserChannel, message);
        }
        // 对不在线的用户，实际实现中应存储到数据库，待上线后通知
        
        // 发送确认给互动者
        switch (interactionType) {
            case LIKE:
                sendSystemMessageToUser(fromUser, "您已点赞该动态");
                break;
            case COMMENT:
                sendSystemMessageToUser(fromUser, "您的评论已发布");
                break;
            case SHARE:
                sendSystemMessageToUser(fromUser, "您已成功分享该动态");
                break;
        }
    }
    
    /**
     * 处理正在输入指示器
     */
    private void handleTypingIndicator(ChatMessage message) throws IOException {
        String toUser = message.getToUser();
        
        Channel toUserChannel = channelMap.get(toUser);
        if (toUserChannel != null && toUserChannel.isActive()) {
            // 直接转发指示器消息给接收者
            send(toUserChannel, message);
        }
    }
    
    /**
     * 处理已读回执
     */
    private void handleReadReceipt(ChatMessage message) throws IOException {
        String toUser = message.getToUser();
        String messageId = message.getRelatedMessageId();
        
        if (messageId == null) {
            return;
        }
        
        Channel toUserChannel = channelMap.get(toUser);
        if (toUserChannel != null && toUserChannel.isActive()) {
            // 发送已读回执给原消息发送者
            message.setRead(true);
            send(toUserChannel, message);
        }
        // 对不在线的用户，实际实现中应存储到数据库
    }
    
    /**
     * 处理媒体传输消息
     * 处理大文件的分块传输
     */
    private void handleMediaTransfer(ChatMessage message) throws IOException {
        String fromUser = message.getFromUser();
        String toUser = message.getToUser();
        
        // 如果是多媒体聊天内容（图片、视频、语音等），执行端到端转发，不存储
        if (!MessageContentType.TEXT.getValue().equals(message.getContentType()) &&
            !message.isRelatedToSocialPost()) {
            
            Channel toUserChannel = channelMap.get(toUser);
            if (toUserChannel != null && toUserChannel.isActive()) {
                // 直接转发给接收者
                send(toUserChannel, message);
                
                // 发送传输确认给发送者
                sendDeliveryConfirmation(fromUser, message.getMessageId(), DeliveryStatus.SENT);
            } else {
                // 接收者不在线，返回错误
                sendErrorToUser(fromUser, "用户" + toUser + "不在线，无法传输媒体内容");
            }
        }
    }
    
    /**
     * 处理媒体传输开始事件
     */
    private void handleMediaTransferStart(ChatMessage message) throws IOException {
        String fromUser = message.getFromUser();
        String toUser = message.getToUser();
        String fileId = message.getFileId();
        
        logger.info("开始媒体传输: 文件ID=" + fileId + ", 从=" + fromUser + ", 到=" + toUser);
        
        // 验证发送者和接收者是否为好友关系
        if (!areFriends(fromUser, toUser)) {
            sendErrorToUser(fromUser, "无法发送文件，对方不是您的好友");
            return;
        }
        
        Channel toUserChannel = channelMap.get(toUser);
        if (toUserChannel != null && toUserChannel.isActive()) {
            // 接收者在线，转发开始传输的通知
            send(toUserChannel, message);
        } else {
            // 接收者不在线，通知发送者
            sendSystemMessageToUser(fromUser, USER_OFFLINE_MESSAGE);
        }
    }
    
    /**
     * 处理媒体传输完成事件
     */
    private void handleMediaTransferComplete(ChatMessage message) throws IOException {
        String fromUser = message.getFromUser();
        String toUser = message.getToUser();
        String fileId = message.getFileId();
        
        logger.info("媒体传输完成: 文件ID=" + fileId);
        
        Channel toUserChannel = channelMap.get(toUser);
        if (toUserChannel != null && toUserChannel.isActive()) {
            // 接收者在线，转发完成通知
            send(toUserChannel, message);
        }
        
        // 通知发送者传输完成
        sendSystemMessageToUser(fromUser, "文件 " + message.getFileName() + " 已成功发送");
    }
    
    /**
     * 发送传递确认消息
     */
    private void sendDeliveryConfirmation(String username, String messageId, DeliveryStatus status) {
        Channel userChannel = channelMap.get(username);
        if (userChannel != null && userChannel.isActive()) {
            ChatMessage confirmationMsg = new ChatMessage();
            confirmationMsg.setType(MessageType.DELIVERY_STATUS.getValue());
            confirmationMsg.setFromUser(SYSTEM_NAME);
            confirmationMsg.setToUser(username);
            confirmationMsg.setContentType(MessageContentType.TEXT.getValue());
            confirmationMsg.setRelatedMessageId(messageId);
            confirmationMsg.setContent(status.getValue());
            confirmationMsg.setTimestamp(System.currentTimeMillis());
            
            send(userChannel, confirmationMsg);
        }
    }
    
    /**
     * 通知好友状态变化（上线/离线）
     */
    private void notifyFriendsOfStatusChange(String username, boolean isOnline) {
        Set<String> friends = friendsMap.getOrDefault(username, Collections.emptySet());
        
        for (String friend : friends) {
            Channel friendChannel = channelMap.get(friend);
            if (friendChannel != null && friendChannel.isActive()) {
                ChatMessage statusMsg = new ChatMessage();
                statusMsg.setType(MessageType.FRIEND_STATUS.getValue());
                statusMsg.setFromUser(username);
                statusMsg.setToUser(friend);
                statusMsg.setContentType(MessageContentType.TEXT.getValue());
                statusMsg.setContent(isOnline ? "online" : "offline");
                statusMsg.setTimestamp(System.currentTimeMillis());
                
                send(friendChannel, statusMsg);
            }
        }
    }
    
    /**
     * 检验消息大小是否超过限制
     */
    private boolean validateMessageSize(ChatMessage message) {
        MessageContentType contentType = MessageContentType.fromString(message.getContentType());
        if (contentType == null) {
            return false;
        }
        
        Long maxSize = MAX_SIZE_LIMITS.get(contentType);
        
        // 针对Base64编码的内容估算实际大小
        if (message.getContent() != null && contentType != MessageContentType.TEXT) {
            // Base64编码的字符串长度大约是原始二进制大小的4/3
            long estimatedSize = (long) (message.getContent().length() * 0.75);
            return maxSize == null || estimatedSize <= maxSize;
        }
        
        return true;
    }
    
    /**
     * 检查两个用户是否为好友关系
     */
    private boolean areFriends(String user1, String user2) {
        Set<String> user1Friends = friendsMap.getOrDefault(user1, Collections.emptySet());
        return user1Friends.contains(user2);
    }
    
    /**
     * 添加好友关系（双向）
     */
    private void addFriend(String user1, String user2) {
        friendsMap.computeIfAbsent(user1, k -> ConcurrentHashMap.newKeySet()).add(user2);
        friendsMap.computeIfAbsent(user2, k -> ConcurrentHashMap.newKeySet()).add(user1);
    }
    
    /**
     * 发送离线消息
     */
    private void sendOfflineMessages(String username) {
        // 实际实现中应从数据库获取离线消息并发送
        // 这里仅作为示例
    }
    
    /**
     * 处理并存储媒体内容，返回URL
     * 注：仅处理朋友圈和头像等允许存储的媒体
     */
    private String processAndStoreMediaContent(ChatMessage message) {
        // 实际实现中应将Base64内容解码并存储到文件系统
        // 然后生成访问URL
        
        String userId = message.getFromUser();
        String contentType = message.getContentType();
        String timestamp = String.valueOf(System.currentTimeMillis());
        
        // 示例URL格式，实际实现应该基于实际存储路径生成
        return "/media/" + contentType + "/" + userId + "/" + timestamp + "/" + message.getMessageId();
    }
    
    /**
     * 处理分块消息的元数据
     */
    private void handleChunkMetadata(ChatMessage message) {
        String messageId = message.getMessageId();
        Integer totalChunks = message.getTotalChunks();
        
        if (messageId == null || totalChunks == null || totalChunks <= 0) {
            logger.warning("无效的分块元数据");
            return;
        }
        
        // 存储元数据和初始化分块缓存
        chunkMetadataCache.put(messageId, message);
        chunkCache.put(messageId, new HashMap<>());
        
        logger.info("收到分块消息元数据: ID=" + messageId + ", 总块数=" + totalChunks);
    }
    
    /**
     * 处理单个消息分块
     */
    private void handleMessageChunk(ChatMessage message) {
        String messageId = message.getMessageId();
        Integer chunkIndex = message.getChunkIndex();
        Integer totalChunks = message.getTotalChunks();
        
        // 日志输出消息内容，帮助调试
        logger.fine("接收到分块消息: " + message.getType() + ", messageId=" + messageId);
        
        if (messageId == null || chunkIndex == null || totalChunks == null) {
            logger.warning("无效的分块消息: 缺少必要的字段");
            return;
        }
        
        // 优先从chunk字段获取内容，如果为空则使用content字段
        String chunk = message.getChunk();
        if (chunk == null) {
            chunk = message.getContent();
        }
        
        // 如果内容为空，则记录错误并返回
        if (chunk == null) {
            logger.warning("无效的分块消息: 内容为空");
            return;
        }
        
        Map<Integer, String> chunks = chunkCache.get(messageId);
        if (chunks == null) {
            logger.warning("未找到分块元数据，忽略分块: " + messageId);
            return;
        }
        
        // 存储当前分块
        chunks.put(chunkIndex, chunk);
        
        logger.fine("收到分块 " + chunkIndex + "/" + totalChunks + " 用于消息 " + messageId);
        
        // 检查是否所有分块都已收到
        if (chunks.size() == totalChunks) {
            try {
                // 所有分块已收到，重组完整消息
                reassembleAndProcessChunkedMessage(messageId);
            } catch (Exception e) {
                logger.log(Level.SEVERE, "重组分块消息失败: " + e.getMessage(), e);
            }
        }
    }
    
    /**
     * 重组并处理分块消息
     */
    private void reassembleAndProcessChunkedMessage(String messageId) throws IOException {
        Map<Integer, String> chunks = chunkCache.get(messageId);
        ChatMessage metadata = chunkMetadataCache.get(messageId);
        
        if (chunks == null || metadata == null) {
            logger.warning("无法找到需要重组的分块消息数据: " + messageId);
            return;
        }
        
        // 按顺序重组所有分块
        StringBuilder fullMessageStr = new StringBuilder();
        for (int i = 0; i < chunks.size(); i++) {
            String chunk = chunks.get(i);
            if (chunk == null) {
                logger.warning("分块 " + i + " 缺失，无法重组消息: " + messageId);
                return;
            }
            fullMessageStr.append(chunk);
        }
        
        try {
            // 解析完整消息
            ChatMessage fullMessage = mapper.readValue(fullMessageStr.toString(), ChatMessage.class);
            
            // 处理重组后的完整消息
            MessageType type = MessageType.fromString(metadata.getOriginalType());
            
            logger.info("成功重组分块消息: ID=" + messageId + ", 类型=" + type);
            
            // 根据消息类型进行处理
            if (type != null) {
                switch (type) {
                    case CHAT_MESSAGE:
                        handleChatMessage(fullMessage);
                        break;
                    case MEDIA_TRANSFER:
                        handleMediaTransfer(fullMessage);
                        break;
                    default:
                        logger.warning("未处理的重组消息类型: " + type);
                }
            }
        } finally {
            // 清理缓存
            chunkCache.remove(messageId);
            chunkMetadataCache.remove(messageId);
        }
    }
    
    /**
     * 为测试用户自动添加好友关系
     */
    private void addTestFriends(String username) {
        // 常用测试用户ID
        List<String> testUsers = Arrays.asList("1", "2", "3", "test", "user1", "user2");
        
        // 如果是测试用户，互相添加为好友
        if (testUsers.contains(username)) {
            for (String testUser : testUsers) {
                // 不需要和自己成为好友
                if (!testUser.equals(username)) {
                    addFriend(username, testUser);
                    logger.info("测试环境：自动添加好友关系 " + username + " <-> " + testUser);
                }
            }
        }
    }
    
    // WebSocket处理器
    private class ChatWebSocketHandler extends SimpleChannelInboundHandler<Object> {
        private WebSocketServerHandshaker handshaker;
        
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
            if (msg instanceof FullHttpRequest) {
                handleHttpRequest(ctx, (FullHttpRequest) msg);
            } else if (msg instanceof WebSocketFrame) {
                handleWebSocketFrame(ctx, (WebSocketFrame) msg);
            }
        }
        
        /**
         * 处理HTTP请求（WebSocket握手）
         */
        private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
            // 检查是否为WebSocket升级请求
            if (!req.headers().contains(HttpHeaderNames.UPGRADE) ||
                !HttpHeaderValues.WEBSOCKET.contentEqualsIgnoreCase(req.headers().get(HttpHeaderNames.UPGRADE))) {
                // 返回普通HTTP响应
                FullHttpResponse res = new DefaultFullHttpResponse(
                    HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
                ctx.channel().writeAndFlush(res);
                return;
            }
            
            // 获取WebSocket路径
            String uri = req.uri();
            if (!uri.startsWith("/ChatMessageServer")) {
                ctx.close();
                return;
            }
            
            // 从查询字符串中提取用户名
            String queryString = uri.contains("?") ? uri.substring(uri.indexOf("?") + 1) : "";
            
            // 完成WebSocket握手
            WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
                getWebSocketLocation(req), null, false);
            handshaker = wsFactory.newHandshaker(req);
            if (handshaker == null) {
                WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
            } else {
                handshaker.handshake(ctx.channel(), req);
                
                // 处理连接打开事件
                handleWebSocketOpen(ctx.channel(), queryString);
            }
        }
        
        /**
         * 获取WebSocket地址
         */
        private String getWebSocketLocation(FullHttpRequest req) {
            String location = req.headers().get(HttpHeaderNames.HOST) + req.uri();
            if (sslEnabled) {
                return "wss://" + location;
            } else {
                return "ws://" + location;
            }
        }
        
        /**
         * 处理WebSocket帧
         */
        private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
            // 关闭帧
            if (frame instanceof CloseWebSocketFrame) {
                handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
                return;
            }
            
            // Ping帧
            if (frame instanceof PingWebSocketFrame) {
                ctx.channel().writeAndFlush(new PongWebSocketFrame(frame.content().retain()));
                return;
            }
            
            // 仅支持文本帧
            if (!(frame instanceof TextWebSocketFrame)) {
                throw new UnsupportedOperationException(
                    "不支持的帧类型: " + frame.getClass().getName());
            }
            
            // 处理文本消息
            String request = ((TextWebSocketFrame) frame).text();
            handleWebSocketMessage(ctx.channel(), request);
        }
        
        /**
         * 通道非活动时调用
         */
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            handleWebSocketClose(ctx.channel());
            super.channelInactive(ctx);
        }
        
        /**
         * 异常处理
         */
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            Channel channel = ctx.channel();
            String username = channel.attr(USERNAME_ATTR).get();
            
            logger.log(Level.SEVERE, "WebSocket错误 " + channel.id().asShortText() + 
                      (username != null ? " (用户: " + username + ")" : ""), cause);
            ctx.close();
        }
    }
    
    /**
     * 分块发送大消息
     */
    private void sendLargeMessage(Channel channel, String message) {
        if (channel == null || !channel.isActive()) {
            return;
        }
        
        try {
            // 分块大小
            final int CHUNK_SIZE = 64 * 1024; // 64KB
            
            // 计算分块数
            int totalChunks = (int) Math.ceil((double) message.length() / CHUNK_SIZE);
            String messageId = "server_" + generateMessageId();
            
            // 发送元数据
            ChatMessage metadataMessage = new ChatMessage();
            metadataMessage.setType("chunk_metadata");
            metadataMessage.setTotalChunks(totalChunks);
            metadataMessage.setMessageId(messageId);
            
            String metadataJson = mapper.writeValueAsString(metadataMessage);
            channel.writeAndFlush(new TextWebSocketFrame(metadataJson));
            
            // 分块发送
            for (int i = 0; i < totalChunks; i++) {
                int start = i * CHUNK_SIZE;
                int end = Math.min((i + 1) * CHUNK_SIZE, message.length());
                String chunk = message.substring(start, end);
                
                ChatMessage chunkMessage = new ChatMessage();
                chunkMessage.setType("chunk");
                chunkMessage.setMessageId(messageId);
                chunkMessage.setChunkIndex(i);
                chunkMessage.setTotalChunks(totalChunks);
                chunkMessage.setContent(chunk);
                
                String chunkJson = mapper.writeValueAsString(chunkMessage);
                channel.writeAndFlush(new TextWebSocketFrame(chunkJson));
                Thread.sleep(50);
            }
        } catch (Exception e) {
            logger.log(Level.SEVERE, "分块发送消息时出错", e);
        }
    }
} 